/*
 * Activiti Modeler component part of the Activiti project Copyright 2005-2014
 * Alfresco Software, Ltd. All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/*
 * Controller for morph shape selection
 */

var KisBpmShapeSelectionCtrl = ['$rootScope', '$scope', '$timeout',
		'$translate', function($rootScope, $scope, $timeout, $translate) {

			$scope.selectedMorphShapes = [];

			$scope.availableMorphShapes = [];

			for (var i = 0; i < $scope.morphShapes.length; i++) {
				if ($scope.morphShapes[i].id != $scope.currentSelectedShape
						.getStencil().idWithoutNs()) {
					$scope.availableMorphShapes.push($scope.morphShapes[i]);
				}
			}

			// Config for grid
			$scope.gridOptions = {
				data : 'availableMorphShapes',
				enableRowReordering : true,
				headerRowHeight : 28,
				multiSelect : false,
				keepLastSelected : false,
				selectedItems : $scope.selectedMorphShapes,
				columnDefs : [{
					field : 'objectId',
					displayName : 'Icon',
					width : 50,
					cellTemplate : 'editor-app/popups/icon-template.html?version='
							+ Date.now()
				}, {
					field : 'name',
					displayName : 'Name'
				}]
			};

			// Click handler for save button
			$scope.select = function() {

				if ($scope.selectedMorphShapes.length > 0) {
					var MorphTo = ORYX.Core.Command.extend({
						construct : function(shape, stencil, facade) {
							this.shape = shape;
							this.stencil = stencil;
							this.facade = facade;
						},
						execute : function() {

							var shape = this.shape;
							var stencil = this.stencil;
							var resourceId = shape.resourceId;

							// Serialize all attributes
							var serialized = shape.serialize();
							stencil.properties().each((function(prop) {
								if (prop.readonly()) {
									serialized = serialized.reject(function(
													serProp) {
												return serProp.name == prop
														.id();
											});
								}
							}).bind(this));

							// Get shape if already created, otherwise create a
							// new shape
							if (this.newShape) {
								newShape = this.newShape;
								this.facade.getCanvas().add(newShape);
							} else {
								newShape = this.facade.createShape({
											type : stencil.id(),
											namespace : stencil.namespace(),
											resourceId : resourceId
										});
							}

							// calculate new bounds using old shape's upperLeft
							// and new shape's width/height
							var boundsObj = serialized.find(function(serProp) {
								return (serProp.prefix === "oryx" && serProp.name === "bounds");
							});

							var changedBounds = null;

							if (!this.facade.getRules().preserveBounds(shape
									.getStencil())) {

								var bounds = boundsObj.value.split(",");
								if (parseInt(bounds[0], 10) > parseInt(
										bounds[2], 10)) { // if lowerRight
															// comes first, swap
															// array items
									var tmp = bounds[0];
									bounds[0] = bounds[2];
									bounds[2] = tmp;
									tmp = bounds[1];
									bounds[1] = bounds[3];
									bounds[3] = tmp;
								}
								bounds[2] = parseInt(bounds[0], 10)
										+ newShape.bounds.width();
								bounds[3] = parseInt(bounds[1], 10)
										+ newShape.bounds.height();
								boundsObj.value = bounds.join(",");

							} else {

								var height = shape.bounds.height();
								var width = shape.bounds.width();

								// consider the minimum and maximum size of
								// the new shape

								if (newShape.minimumSize) {
									if (shape.bounds.height() < newShape.minimumSize.height) {
										height = newShape.minimumSize.height;
									}

									if (shape.bounds.width() < newShape.minimumSize.width) {
										width = newShape.minimumSize.width;
									}
								}

								if (newShape.maximumSize) {
									if (shape.bounds.height() > newShape.maximumSize.height) {
										height = newShape.maximumSize.height;
									}

									if (shape.bounds.width() > newShape.maximumSize.width) {
										width = newShape.maximumSize.width;
									}
								}

								changedBounds = {
									a : {
										x : shape.bounds.a.x,
										y : shape.bounds.a.y
									},
									b : {
										x : shape.bounds.a.x + width,
										y : shape.bounds.a.y + height
									}
								};

							}

							var oPos = shape.bounds.center();
							if (changedBounds !== null) {
								newShape.bounds.set(changedBounds);
							}

							// Set all related dockers
							this.setRelatedDockers(shape, newShape);

							// store DOM position of old shape
							var parentNode = shape.node.parentNode;
							var nextSibling = shape.node.nextSibling;

							// Delete the old shape
							this.facade.deleteShape(shape);

							// Deserialize the new shape - Set all attributes
							newShape.deserialize(serialized);
							/*
							 * Change color to default if unchanged 23.04.2010
							 */
							if (shape.getStencil().property("oryx-bgcolor")
									&& shape.properties["oryx-bgcolor"]
									&& shape.getStencil()
											.property("oryx-bgcolor").value()
											.toUpperCase() == shape.properties["oryx-bgcolor"]
											.toUpperCase()) {
								if (newShape.getStencil()
										.property("oryx-bgcolor")) {
									newShape.setProperty("oryx-bgcolor",
											newShape.getStencil()
													.property("oryx-bgcolor")
													.value());
								}
							}
							if (changedBounds !== null) {
								newShape.bounds.set(changedBounds);
							}

							if (newShape.getStencil().type() === "edge"
									|| (newShape.dockers.length == 0 || !newShape.dockers[0]
											.getDockedShape())) {
								newShape.bounds.centerMoveTo(oPos);
							}

							if (newShape.getStencil().type() === "node"
									&& (newShape.dockers.length == 0 || !newShape.dockers[0]
											.getDockedShape())) {
								this.setRelatedDockers(newShape, newShape);

							}

							// place at the DOM position of the old shape
							if (nextSibling)
								parentNode.insertBefore(newShape.node,
										nextSibling);
							else
								parentNode.appendChild(newShape.node);

							// Set selection
							this.facade.setSelection([newShape]);
							this.facade.getCanvas().update();
							this.facade.updateSelection();
							this.newShape = newShape;

						},
						rollback : function() {

							if (!this.shape || !this.newShape
									|| !this.newShape.parent) {
								return;
							}

							// Append shape to the parent
							this.newShape.parent.add(this.shape);
							// Set dockers
							this.setRelatedDockers(this.newShape, this.shape);
							// Delete new shape
							this.facade.deleteShape(this.newShape);
							// Set selection
							this.facade.setSelection([this.shape]);
							// Update
							this.facade.getCanvas().update();
							this.facade.updateSelection();
						},

						/**
						 * Set all incoming and outgoing edges from the shape to
						 * the new shape
						 * 
						 * @param {Shape}
						 *            shape
						 * @param {Shape}
						 *            newShape
						 */
						setRelatedDockers : function(shape, newShape) {

							if (shape.getStencil().type() === "node") {

								(shape.incoming || []).concat(shape.outgoing
										|| []).each(function(i) {
									i.dockers.each(function(docker) {
										if (docker.getDockedShape() == shape) {
											var rPoint = Object
													.clone(docker.referencePoint);
											// Move reference point per percent

											var rPointNew = {
												x : rPoint.x
														* newShape.bounds
																.width()
														/ shape.bounds.width(),
												y : rPoint.y
														* newShape.bounds
																.height()
														/ shape.bounds.height()
											};

											docker.setDockedShape(newShape);
											// Set reference point and center to
											// new position
											docker.setReferencePoint(rPointNew);
											if (i instanceof ORYX.Core.Edge) {
												docker.bounds
														.centerMoveTo(rPointNew);
											} else {
												var absXY = shape.absoluteXY();
												docker.bounds.centerMoveTo({
															x : rPointNew.x
																	+ absXY.x,
															y : rPointNew.y
																	+ absXY.y
														});
												// docker.bounds.moveBy({x:rPointNew.x-rPoint.x,
												// y:rPointNew.y-rPoint.y});
											}
										}
									});
								});

								// for attached events
								if (shape.dockers.length > 0
										&& shape.dockers.first()
												.getDockedShape()) {
									newShape.dockers.first()
											.setDockedShape(shape.dockers
													.first().getDockedShape());
									newShape.dockers
											.first()
											.setReferencePoint(Object
													.clone(shape.dockers
															.first().referencePoint));
								}

							} else { // is edge
								newShape.dockers.first()
										.setDockedShape(shape.dockers.first()
												.getDockedShape());
								newShape.dockers.first()
										.setReferencePoint(shape.dockers
												.first().referencePoint);
								newShape.dockers.last()
										.setDockedShape(shape.dockers.last()
												.getDockedShape());
								newShape.dockers
										.last()
										.setReferencePoint(shape.dockers.last().referencePoint);
							}
						}
					});

					var stencil = undefined;
					var stencilSets = $scope.editor.getStencilSets().values();

					var stencilId = $scope.selectedMorphShapes[0].id;
					if ($scope.selectedMorphShapes[0].genericTaskId) {
						stencilId = $scope.selectedMorphShapes[0].genericTaskId;
					}

					for (var i = 0; i < stencilSets.length; i++) {
						var stencilSet = stencilSets[i];
						var nodes = stencilSet.nodes();
						for (var j = 0; j < nodes.length; j++) {
							if (nodes[j].idWithoutNs() === stencilId) {
								stencil = nodes[j];
								break;
							}
						}
					}

					if (!stencil)
						return;

					// Create and execute command (for undo/redo)
					var command = new MorphTo($scope.currentSelectedShape,
							stencil, $scope.editor);
					$scope.editor.executeCommands([command]);
				}

				$scope.close();
			};

			$scope.cancel = function() {
				$scope.$hide();
			};

			// Close button handler
			$scope.close = function() {
				$scope.$hide();
			};

		}];